/*
 *  qun.c
 *
 *  QQ Qun
 *
 *  Copyright (C) 2008  Huang Guan
 *
 *  2008-7-12 Created.
 *
 *  Description: This file mainly includes the functions about 
 *  Qun
 *
 */

#include <time.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include "qqclient.hpp"

#include "debug.hpp"
#include "protocol.hpp"
#include "buddy.hpp"
#include "qun.hpp"


namespace {

struct qun_searcher:public std::binary_function<qqqun*,uint,bool>{
	bool operator() (const qqqun *p,  uint v) const{
		return p->number ==v ;
	}
};
struct member_searcher:public std::binary_function<const qunmember*,uint,bool>{
	bool operator() (const qunmember *p,  uint v) const{
		return p->number ==v ;
	}

};

struct qun_ext_searcher:public std::binary_function<qqqun*,uint,bool>{
	bool operator() (const qqqun *p,  uint v) const{
		return p->ext_number ==v ;
	}

};

struct qun_kill_members:public std::unary_function<qqqun*,void>{
	void operator() (qqqun *q) {
		q->member_list_lock.lock();
		for(qqqun::member_list_type::iterator i = q->member_list.begin();i != q->member_list.end(); ++i)
			delete *i;
		q->member_list.clear();
		q->member_list_lock.unlock();
	}
};

//更新所有的群信息2009-1-25 11:58
//Update all qun information
struct  qun_update_searcher:public std::binary_function<qqqun*,qqclient*,void>
{
	void operator() (qqqun *p,  qqclient* v) const{
		qun_update_info( v, p );
	}	
};

struct  qun_update_online_searcher:public std::binary_function<qqqun*,qqclient*,void>
{
	void operator() (qqqun *p,  qqclient* v) const{
		qun_update_online( v, p );
	}	
};

}

qunmember* qun_member_get( qqclient* qq, qqqun* q, uint number, int create )
{
	if( !number )
		return NULL;
	q->member_list_lock.lock();
	qunmember* m=NULL;
	qqqun::member_list_type::iterator i=std::find_if(q->member_list.begin(),q->member_list.end(),std::bind2nd(member_searcher(),number));
	if(i!=q->member_list.end()) m=*i;
	//if not found, m must be NULL
	if( !m && create ){
		m=new qunmember();
		m->number = number;
		sprintf( m->nickname, "%u", number );
		q->member_list.push_back(m);		
	}
	q->member_list_lock.unlock();
	return m;
}

void qun_member_remove( qqclient* qq, qqqun* q, uint number )
{
	q->member_list_lock.lock();	
	qqqun::member_list_type::iterator i=std::find_if(q->member_list.begin(),q->member_list.end(),std::bind2nd(member_searcher(),number));
	if(i!=q->member_list.end()) {
		q->member_list.erase(i);
	}
	q->member_list_lock.unlock();
}

qqqun* qun_get(qqclient* qq, uint number, int create )
{
	if( !number )
		return NULL;

	qqqun* q=NULL;
	qq->qun_list_lock.lock();
	qqclient::qun_list_type::iterator i=std::find_if(qq->qun_list.begin(),qq->qun_list.end(),std::bind2nd(qun_searcher(),number));
	if(i!=qq->qun_list.end()) q=*i;
	//if not found, b must be NULL
	if( !q && create ){
		q=new qqqun();
		q->number = number;
		qsnprintf( q->name, sizeof(q->name),"%u", number );
		qq->qun_list.push_back(q);
		qunmember* m = qun_member_get( qq, q, qq->number, 1 );
		if( m ){
			qstrncpy( m->nickname, qq->self->nickname,sizeof(m->nickname) );
			m->status = qq->self->status;
		}	
	}
	qq->qun_list_lock.unlock();
	return q;
}


qqqun* qun_get_by_ext( qqclient* qq, uint ext_number )
{	
	qqqun* q=NULL;
	qq->qun_list_lock.lock();
	qqclient::qun_list_type::iterator i=std::find_if(qq->qun_list.begin(),qq->qun_list.end(),std::bind2nd(qun_ext_searcher(),ext_number));
	if(i!=qq->qun_list.end()) q=*i;
	qq->qun_list_lock.unlock();
	return q;
}

void qun_remove( qqclient* qq, uint number )
{
	qqqun* q=NULL;
	qq->qun_list_lock.lock();
	qqclient::qun_list_type::iterator i=std::find_if(qq->qun_list.begin(),qq->qun_list.end(),std::bind2nd(qun_searcher(),number));
	if(i!=qq->qun_list.end()) q=*i;
	if( q ){
		qq->qun_list.erase(i);
	}
	qq->qun_list_lock.unlock();

	q->member_list_lock.lock();
	for(qqqun::member_list_type::iterator i = q->member_list.begin();i != q->member_list.end(); ++i)
		delete *i;
	q->member_list.clear();
	q->member_list_lock.unlock();	
}



void qun_member_cleanup( qqclient* qq )
{	
	//先取出当前群列表的一份copy。然后就可以释放锁。
	qq->qun_list_lock.lock();
	qqclient::qun_list_type qunlist=qq->qun_list;
	qq->qun_list.clear();
	qq->qun_list_lock.unlock();
	//遍历这份copy，挨个释放群成员。
	std::for_each(qunlist.begin(),qunlist.end(),qun_kill_members());
}

void qun_update_info( qqclient* qq, qqqun* q )
{
	prot_qun_get_info( qq, q->number, 0 );
}


void qun_update_memberinfo( qqclient* qq, qqqun* q )
{
	std::vector<uint> numbers;
	q->member_list_lock.lock();
	for(qqqun::member_list_type::iterator i=q->member_list.begin();i!=q->member_list.end();++i){
		numbers.push_back((*i)->number);
	}
	q->member_list_lock.unlock();
	
	int count = numbers.size();
	int send;
	std::vector<uint>::iterator v = numbers.begin();
	while( count > 0 ){
		send = 30;	//don't larger than 30, specified in prot_qun.c
		if( count < send ) send = count;
		prot_qun_get_memberinfo( qq, q->number, v, send );
		v += send;
		count -= send;
	}
}

void qun_update_online( qqclient* qq, qqqun* q )
{
	prot_qun_get_online( qq, q->number );
}

void qun_set_members_off( qqclient* qq, qqqun* q )
{	
	q->member_list_lock.lock();
	for(qqqun::member_list_type::iterator i=q->member_list.begin();i!=q->member_list.end();++i){
		(*i)->status=QQ_OFFLINE;
	}
	q->member_list_lock.unlock();
}


int qun_send_message( qqclient* qq, uint number, char* msg )
{
	prot_qun_send_msg( qq, number, msg );
	return 0;
}

void qun_put_single_event( qqclient* qq, qqqun* q )
{
	const size_t tmpSize=KB(128);
	char *temp=new char[tmpSize ];

	qunmember* m;
	sprintf( temp, "clusterinfo^$%u^$%s^$%s^$%s^$", q->ext_number, q->name, q->ann, q->intro );
	q->member_list_lock.lock();
	for(size_t i=0; i<q->member_list.size(); i++ ){
		m = (qunmember*)q->member_list[i];
		qsnprintf( temp,tmpSize-1, "%s%u\t%s\t%s\t%d^@", temp, m->number, m->nickname, buddy_status_string( m->status ),
			m->role );
	}
	q->member_list_lock.unlock();
	qqclient_put_event( qq, temp );
	delete[] temp ;
}

void qun_put_event( qqclient* qq )
{
	qqqun* q;
	qq->qun_list_lock.lock();	
	for(size_t i=0; i<qq->qun_list.size(); i++ ){
		q = (qqqun*)qq->qun_list[i];
		qun_put_single_event( qq, q );
	}
	qq->qun_list_lock.unlock();
}


void qun_update_all( qqclient* qq )
{
	qq->qun_list_lock.lock();
	std::for_each(qq->qun_list.begin(),qq->qun_list.end(),std::bind2nd(qun_update_searcher(),qq));	
	qq->qun_list_lock.unlock();
}


void qun_update_online_all( qqclient* qq )
{	
	qq->qun_list_lock.lock();
	std::for_each(qq->qun_list.begin(),qq->qun_list.end(),std::bind2nd(qun_update_online_searcher(),qq));	
	qq->qun_list_lock.unlock();
}
